#include "../include/command.h"
#include "../include/linkstack.h"
#include <crypt.h>
#include <shadow.h>

#define INFO_LEN 16
// 切割地址
void parseDir(char *dir_path, LStack_7th *stack);

// 拼接地址
int strcatDir(LStack_7th *stack, char **dest_dir);

// 检查路径是否存在
int checkDir(const char *root_dir, const char *current_dir, int *isdir);

int rmDirPlus(char *dir_path);

// 实现目录跳转
// root_dir是仓库的绝对路径,current_dir是用户的当前所在路径如:/lyh/cpp66/
// dest_dir 是跳转的路径
// commandresult是执行的结果
int command_cd(const char *root_dir, const char *current_dir, char *dest_dir,
			   commandResult_t *result) {
	result->result = (char *)calloc(INFO_LEN, sizeof(char));
	if (root_dir == NULL || current_dir == NULL || result == NULL) {
		sprintf(result->result, "参数有null");
		return -1;
	}
	int is_dir = 0;
	// 获取绝对路径，用于验证是否存在
	if (checkDir(root_dir, current_dir, &is_dir)) {
		sprintf(result->result, "当前目录不存在");
		return -1;
	}

	// 获得最终的相对路径
	LStack_7th stack = {0};
	parseDir((char *)current_dir, &stack);

	// 处理dest_dir;
	char *token, *saveptr;
	token = strtok_r(dest_dir, "/", &saveptr);
	while (token) {
		DT_7th it = {0};
		if (strcmp(token, "..") == 0) {
			pullLStack_7th(&stack, &it);
		} else if (strcmp(token, ".") == 0)
			continue;
		else {
			it.dir_item = token;
			pushLStack_7th(&stack, &it);
		}
		token = strtok_r(NULL, "/", &saveptr);
	}
	if (stack.size <= 0) {
		sprintf(result->result, "跳转路径越界");
		return -1;
	}
	result->ls_linenum = 1;
	result->result_ls = calloc(1, sizeof(char *));
	strcatDir(&stack, result->result_ls);

	if (checkDir(root_dir, result->result_ls[0], &is_dir)) {
		sprintf(result->result, "当前目录不存在");
		return -1;
	}
	if (is_dir) {
		strcat(result->result_ls[0], "/");
		return 0;
	}
	sprintf(result->result, "是文件不可跳转");
	return 1;
}

// 实现目录删除
// root_dir是仓库的绝对路径,current_dir是用户的当前所在路径如:/lyh/cpp66/
// dest_dir 是删除的目标文件或者目录
// commandresult是执行的结果
int command_remove(const char *root_dir, const char *current_dir,
				   const char *dest_dir, commandResult_t *result) {
	if (command_cd(root_dir, current_dir, (char *)dest_dir, result) == -1)
		return -1;
	char *real_path = calloc(
		strlen(root_dir) + strlen(result->result_ls[0] + 2), sizeof(char));
	strcat(real_path, root_dir);
	strcat(real_path, result->result_ls[0]);
	int tag = rmDirPlus(real_path);
	free(real_path);
	bzero(result->result, INFO_LEN);
	if (tag == 0) {
		result->ret = 0;
		sprintf(result->result, "删除成功");
	} else {
		result->ret = 1;
		sprintf(result->result, "删除失败");
		return -1;
	}
	free(result->result_ls[0]);
	free(result->result_ls);
	return 0;
}

void parseDir(char *dir_path, LStack_7th *stack) {
	initLStack_7th(stack);
	char *token, *saveptr;
	token = strtok_r(dir_path, "/", &saveptr);
	while (token != NULL) {

		DT_7th item = {0};
		item.dir_item = token;
		pushLStack_7th(stack, &item);
		token = strtok_r(NULL, "/", &saveptr);
	}
}

int strcatDir(LStack_7th *stack, char **dest_dir) {
	if (stack == NULL || stack->size <= 0 || dest_dir == NULL)
		return -1;

	DT_7th it = {0};
	LStack_7th stack1;
	initLStack_7th(&stack1);
	int lengh = 0;
	while (pullLStack_7th(stack, &it) == 0) {
		lengh += strlen(it.dir_item) + 1;
		pushLStack_7th(&stack1, &it);
	}
	*dest_dir = calloc(lengh + 2, sizeof(char));

	while (pullLStack_7th(&stack1, &it) == 0) {
		strcat(*dest_dir, it.dir_item);
		if (stack1.size)
			strcat(*dest_dir, "/");
	}
	freeDTitem_7th(&it);
	return 0;
}

int checkDir(const char *root_dir, const char *current_dir, int *is_dir) {
	// 获取绝对路径，用于验证是否存在
	char *real_path = (char *)calloc(strlen(root_dir) + strlen(current_dir) + 1,
									 sizeof(char));
	strncpy(real_path, root_dir, strlen(root_dir));
	strncat(real_path, current_dir, strlen(current_dir));
	if (access(real_path, F_OK)) {
		free(real_path);
		return -1;
	}
	struct stat stt;
	stat(real_path, &stt);
	if (S_ISDIR(stt.st_mode))
		*is_dir = 1;
	else
		*is_dir = 0;
	free(real_path);
	return 0;
}

int rmDirPlus(char *path) {
	struct stat sta;
	stat(path, &sta);
	if (!S_ISDIR(sta.st_mode)) {
		if (remove(path) == 0)
			return 0;
		else
			return -1;
	}
	DIR *dir;
	struct dirent *entry;
	char full_path[1024];

	if ((dir = opendir(path)) == NULL) {
		perror("Error opening directory");
		return -1;
	}

	while ((entry = readdir(dir)) != NULL) {
		if (strcmp(entry->d_name, ".") == 0 ||
			strcmp(entry->d_name, "..") == 0) {
			continue;
		}

		// 拼接新的地址
		snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name);

		struct stat statbuf;
		if (stat(full_path, &statbuf) == -1) {
			perror("Error getting file status");
			closedir(dir);
			return -1;
		}

		if (S_ISDIR(statbuf.st_mode)) {
			if (rmDirPlus(full_path) == -1) {
				closedir(dir);
				return -1;
			}
		} else {
			if (remove(full_path) == -1) {
				perror("Error deleting file");
				closedir(dir);
				return -1;
			}
		}
	}

	closedir(dir);

	// 删除当前目录
	if (rmdir(path) == -1) {
		perror("Error deleting directory");
		return -1;
	}

	return 0;
}

// 校验用户是否是系统用户，密码是明文
int command_verif(char username[], char passwd[]) {
	if (username == NULL || passwd == NULL)
		return -1;
	FILE *fp = fopen("/etc/shadow", "r");
	if (!fp) {
		perror("Failed to open /etc/shadow");
		return 1;
	}
	struct spwd *sp;
	sp = getspnam(username);
	if (sp == NULL) {
		printf("user no exit\n");
		return -1;
	}

	char line[1024];
	char *shadow_user = calloc(strlen(username) + 2, sizeof(char));
	sprintf(shadow_user, "%s:", username);

	// 查找用户
	while (fgets(line, sizeof(line), fp)) {
		if (strncmp(line, shadow_user, strlen(shadow_user)) == 0) {

			// 去头去尾
			char *hash = strtok(line + strlen(shadow_user), ":");
			char *salt_end = strrchr(hash, '$');
			if (salt_end) {
				*salt_end = '\0';
			}

			char *pp = crypt(passwd, hash);

			printf("%s\n", pp);
			printf("%s\n", sp->sp_pwdp);
			if (strcmp(pp, sp->sp_pwdp)) {
				return 1;
			}
			return 0;
		}
	}
	free(shadow_user);
	fclose(fp);
	return -1;
}
